package com.kmzx.one.project.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.google.gson.Gson;
import com.kmzx.one.common.constants.Constants;
import com.kmzx.one.common.enums.DeletedEnum;
import com.kmzx.one.common.enums.IdCardEnum;
import com.kmzx.one.common.enums.SameWxEnum;
import com.kmzx.one.common.exceptions.NoSuchObjectException;
import com.kmzx.one.common.utils.HttpClientUtil;
import com.kmzx.one.common.utils.IdCardUtil;
import com.kmzx.one.common.utils.StringUtils;
import com.kmzx.one.common.utils.UUIDGenerator;
import com.kmzx.one.project.config.data.AliConfig;
import com.kmzx.one.project.config.data.QiNiuConfig;
import com.kmzx.one.project.config.data.WXDataConfig;
import com.kmzx.one.project.entity.ChannelActivity;
import com.kmzx.one.project.entity.UserAuthentication;
import com.kmzx.one.project.entity.UserBankCert;
import com.kmzx.one.project.entity.UserInvite;
import com.kmzx.one.project.entity.UserMessage;
import com.kmzx.one.project.entity.UserProfit;
import com.kmzx.one.project.entity.UserRank;
import com.kmzx.one.project.entity.UserShareMini;
import com.kmzx.one.project.entity.UserVerify;
import com.kmzx.one.project.entity.WxUser;
import com.kmzx.one.project.events.ShareMiniEvent;
import com.kmzx.one.project.mapper.CustomerMapper;
import com.kmzx.one.project.mapper.ExpandUserMapper;
import com.kmzx.one.project.mapper.UserAuthenticationMapper;
import com.kmzx.one.project.mapper.UserInviteMapper;
import com.kmzx.one.project.mapper.UserMessageMapper;
import com.kmzx.one.project.mapper.UserProfitMapper;
import com.kmzx.one.project.mapper.UserRankMapper;
import com.kmzx.one.project.mapper.WxPayMapper;
import com.kmzx.one.project.mapper.WxUserMapper;
import com.kmzx.one.project.others.common.WxSeaGateResponse;
import com.kmzx.one.project.others.dso.OrderBeSendDso;
import com.kmzx.one.project.others.dso.RankUserDso;
import com.kmzx.one.project.others.dso.UserRankDso;
import com.kmzx.one.project.others.dto.FansInfo;
import com.kmzx.one.project.others.dto.UserAuthInfo;
import com.kmzx.one.project.others.dto.UserCenterInfo;
import com.kmzx.one.project.others.dto.UserCert;
import com.kmzx.one.project.others.dto.UserCertInfo;
import com.kmzx.one.project.others.dto.UserProfitInfo;
import com.kmzx.one.project.others.dto.UserVerifyInfo;
import com.kmzx.one.project.others.dto.WXSeaInfo;
import com.kmzx.one.project.others.wxo.MySelfCodeUnLimit;
import com.kmzx.one.project.service.UserCenterService;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import weixin.popular.api.TokenAPI;
import weixin.popular.api.WxaAPI;
import weixin.popular.bean.token.Token;
import weixin.popular.bean.wxa.LineColor;
import weixin.popular.client.LocalHttpClient;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Service
public class UserCenterServiceImpl implements UserCenterService {

    @Autowired
    private WxUserMapper wxUserMapper;

    @Autowired
    private UserRankMapper userRankMapper;

    @Autowired
    private UserProfitMapper userProfitMapper;

    @Autowired
    private UserInviteMapper userInviteMapper;

    @Autowired
    private CustomerMapper customerMapper;

    @Autowired
    UserAuthenticationMapper userAuthenticationMapper;

    @Autowired
    private RedisTemplate<String, Object> stringObjectRedisTemplate;

    // 数据配置
    @Autowired
    private QiNiuConfig qiNiuConfig;

    @Autowired
    private WXDataConfig wxConfig;

    @Autowired
    AliConfig aliConfig;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    WxPayMapper wxPayMapper;

    @Autowired
    UserMessageMapper userMessageMapper;


    @Autowired
    ExpandUserMapper expandUserMapper;


    @Override
    public WxUser findByOpenId(String openId) throws Exception {
        WxUser wxUser = wxUserMapper.selectByOpenId(openId);
        return wxUser;
    }

    @Override
    public WxUser doInsertWxUser(WxUser wxUser, String parent) throws Exception {
        String useId = wxUser.getId();
        String s = UUIDGenerator.generate();
        if (useId != null) {
            s = useId;
        }
        Date date = new Date();
        List<RankUserDso> userDtoList = wxUserMapper.selectUserRankTabNo();
        if (!CollectionUtils.isEmpty(userDtoList)) {
            userDtoList.sort(Comparator.comparing(RankUserDso::getRankNum));
            String rankId = userDtoList.get(0).getRankId();
            UserRank userRank = new UserRank();
            userRank.setUserId(s);
            userRank.setCreateTime(date);
            userRank.setUpdateTime(date);
            userRank.setDeleted(0);
            userRank.setId(UUIDGenerator.generate());
            userRank.setMyGrowthValue(0.0);
            userRank.setRankId(rankId);

            UserProfit profit = new UserProfit();
            profit.setId(UUIDGenerator.generate());
            profit.setUserId(s);
            profit.setCreateTime(date);
            profit.setDeleted(0);
            profit.setProfitMoney(BigDecimal.ZERO);
            profit.setAccountMoney(BigDecimal.ZERO);
            profit.setStates(0);
            profit.setUpdateTime(date);

            userRankMapper.insert(userRank);
            userProfitMapper.insert(profit);

            logger.info("-----------初始化用户的资金账户:{},以及等级账户:{}", profit, userRank);
        }


        wxUser.setId(s);
        wxUser.setCreateTime(date);
        wxUser.setUpdateTime(date);
        wxUser.setDeleted(0);
        wxUser.setStates(0);


        if (StringUtils.isNotEmpty(parent)) {
            UserInvite userInvite = new UserInvite();
            userInvite.setId(UUIDGenerator.generate());
            userInvite.setCreateTime(date);
            userInvite.setUpdateTime(date);
            userInvite.setFromUser(parent);
            userInvite.setToUser(s);
            userInvite.setStates(0);
            userInviteMapper.insert(userInvite);
            logger.info("-----------初始化用户的邀请人:{}", userInvite);

            UserMessage uMsg = new UserMessage();
            uMsg.setId(UUIDGenerator.generate())
                    .setCreateTime(date)
                    .setUpdateTime(date)
                    .setDeleted(0)
                    .setUserId(parent)
                    .setFromUser("快美小助手")
                    .setReading(0)
                    .setReading(0);
            uMsg.setTitle("恭喜! 【" + wxUser.getNickName() + "】成为您的粉丝!");
            uMsg.setContent("您的粉丝购买商品后，您将获得收益，粉丝越多收益越多。快去邀请更多好友成为您的粉丝吧~");
            uMsg.setTypes(0).setForwards(1)
                    .setKinds(1)
                    .setImgUrl("")
                    .setLinkUrl("/pages/zsfs/zsfs");

            userMessageMapper.insertUserMessage(uMsg);
            logger.info("-----------给邀请人发送通知消息:{}", uMsg);
        } else {
            // 初始化为官方号
//            UserInvite userInvite = new UserInvite();
//            userInvite.setId(UUIDGenerator.generate());
//            userInvite.setCreateTime(date);
//            userInvite.setUpdateTime(date);
//            userInvite.setFromUser(" ");
//            userInvite.setToUser(s);
//            userInvite.setStates(0);
//            userInviteMapper.insert(userInvite);
        }
        wxUserMapper.insertWxUser(wxUser);

        Integer identityType = wxUser.getIdentityType();
        if(identityType!=null && identityType!=0){
            ChannelActivity channelActivity = expandUserMapper.selectChannelActivityById(String.valueOf(identityType));
            Integer visitorsNum = channelActivity.getVisitorsNum();
            channelActivity.setVisitorsNum(visitorsNum+1);
            expandUserMapper.updateChannelActivity2(channelActivity);
        }

        logger.info("-----------初始化用户账号:{}", wxUser);
        return wxUser;
    }

    @Override
    public Integer doUpdateWxUser(WxUser wxUser) throws Exception {
        Integer result = wxUserMapper.doUpdateWxUser(wxUser);
        return result;
    }

    @Override
    public UserCenterInfo findUserTopInfo(String userId) throws Exception {
        UserCenterInfo userInfo = wxUserMapper.selectUserTopInfo(userId);
        if (userInfo != null) {
            Integer rankNum = userInfo.getRankNum();
            userInfo.setOneFans(0);
            userInfo.setAllFans(0);
            userInfo.setTotalIncome(BigDecimal.ZERO);
            Double seaRankRate = userInfo.getSeaRankRate();
            if (seaRankRate == null) {
                userInfo.setSeaRankRate(1.0);
            }
            int num = userInviteMapper.selectUserInviteNum(userId);
            userInfo.setOneFans(num);
            userInfo.setAllFans(num);
//            Page<FansInfo> pager = userInviteMapper.selectUserFans(userId, null);
//
//            if (!CollectionUtils.isEmpty(pager)) {
//                List<FansInfo> result = pager.getResult();
//                int size = result.size();
//                userInfo.setOneFans(size);
//                userInfo.setAllFans(size);
//                if (size > 0) {
////                    List<FansInfo> fansInfos = haveNext(userId);
////                    if (fansInfos != null && fansInfos.size() > 0) {
////                        userInfo.setAllFans(fansInfos.size());
////                    }
//
////                    List<String> fansInfos = haveNext2(userId);
////                    if (fansInfos != null && fansInfos.size() > 0) {
////                        userInfo.setAllFans(fansInfos.size());
////                    }
//
//
//                }
//            }
            if (rankNum != 0) {
                userInfo.setTotalIncome(getUserProfit(userId));
            } else {
                userInfo.setRankRate(BigDecimal.valueOf(userInfo.getSeaRankRate()));
            }
//                List<UserFansDso> fans = wxUserMapper.selectUserL1Fans(userId);
//                if (!CollectionUtils.isEmpty(fans)) {
//                    userInfo.setOneFans(fans.size());
//                    if (rankNum == 1) {
//                        userInfo.setAllFans(fans.size());
//                    }
//
//                    if (rankNum == 2) {
//                        List<String> collect = fans.stream().filter(fs -> fs.getLevels() == 1).map(fss -> fss.getUserId()).collect(Collectors.toList());
//                        if (!CollectionUtils.isEmpty(collect)) {
//                            List<UserFansDso> allFans = wxUserMapper.selectUserAllFans(collect);
//                            userInfo.setAllFans(allFans.size() + fans.size());
//                        } else {
//                            userInfo.setAllFans(fans.size());
//                        }
//
//                    }
//
//                    if (rankNum == 3) {
//                        List<String> collect = fans.stream().filter(fs -> fs.getLevels() == 2).map(fss -> fss.getUserId()).collect(Collectors.toList());
//                        if (!CollectionUtils.isEmpty(collect)) {
//                            List<UserFansDso> allFans = wxUserMapper.selectUserAllFans(collect);
//                            userInfo.setAllFans(allFans.size() + fans.size());
//                        } else {
//                            userInfo.setAllFans(fans.size());
//                        }
//
//                        List<String> collect1 = fans.stream().filter(fs -> fs.getLevels() == 1).map(fss -> fss.getUserId()).collect(Collectors.toList());
//                        if (!CollectionUtils.isEmpty(collect1)) {
//                            List<UserFansDso> allFans = wxUserMapper.selectUserAllFans(collect1);
//                            int allFans1 = userInfo.getAllFans();
//                            userInfo.setAllFans(allFans.size() + allFans1);
//                        }
//                    }
//                }

            List<UserRankDso> tabs = userRankMapper.selectAllRankTabs();
            for (int i = 0; i < tabs.size(); i++) {
                if (tabs.get(i).getRankId().equals(userInfo.getRankId()) && i != tabs.size() - 1) {
                    userInfo.setNextName(tabs.get(i + 1).getRankName());
                    userInfo.setNextMoney(tabs.get(i + 1).getRankPay());
                    break;
                }
            }
        }
        List<OrderBeSendDso> userTwoInfo = wxUserMapper.selectUserTwoInfo(userId);

        if (!CollectionUtils.isEmpty(userTwoInfo) && userTwoInfo.size() > 0) {
            for (OrderBeSendDso beSendDto : userTwoInfo) {
                Integer states = beSendDto.getStates();
                if (states == 0) {
                    userInfo.setBePaid(beSendDto.getNumbers());
                }
                if (states == 2) {
                    userInfo.setBeAccepted(beSendDto.getNumbers());
                }
                if (states == 1) {
                    userInfo.setBeSend(beSendDto.getNumbers());
                }
            }
        }
        int i = wxUserMapper.countOldFans(userId);
        // TODO 直属=all
        userInfo.setAllFans(userInfo.getOneFans());
        userInfo.setBeforeFans(i);
        return userInfo;
    }

    @Override
    public UserCenterInfo findUserTwoInfo(String userId) throws Exception {
        List<OrderBeSendDso> userTwoInfo = wxUserMapper.selectUserTwoInfo(userId);
        if (!CollectionUtils.isEmpty(userTwoInfo) && userTwoInfo.size() > 0) {
            UserCenterInfo dto = new UserCenterInfo();
            for (OrderBeSendDso beSendDto : userTwoInfo) {
                Integer states = beSendDto.getStates();
                if (states == 0) {
                    dto.setBePaid(beSendDto.getNumbers());
                }
                if (states == 1) {
                    dto.setBeSend(beSendDto.getNumbers());
                }
                if (states == 2) {
                    dto.setBeAccepted(beSendDto.getNumbers());
                }
            }
            return dto;
        } else {
            throw new NoSuchObjectException(201, "暂无数据");
        }
    }

    @Override
    public Integer doHasFather(String userId) throws Exception {
        UserCenterInfo userInfo = wxUserMapper.selectUserTopInfo(userId);
        Integer rankNum = userInfo.getRankNum();
        if (rankNum == 0) {
            int count = wxUserMapper.hasTop(userId);
            if (count == 0) {
                // 1 代表没有邀请人
                // 0 代表  有邀请人
                return 1;
            }
        }
        return 0;
    }

    @Override
    public UserAuthInfo doCheckUserAuth(String userId) throws Exception {
        List<UserAuthInfo> infos = customerMapper.checkUserAuth(userId);

        if (CollectionUtils.isEmpty(infos)) {
            UserAuthInfo info = new UserAuthInfo();
            // 1 代表没有认证
            info.setHas(1);
            return info;
        } else {
            UserAuthInfo userAuthInfo = infos.get(0);
            String idCard = userAuthInfo.getIdCard();
//            idCard.su
            UserProfitInfo profit = customerMapper.selectUserProfit(userId);
            if (profit != null) {
                userAuthInfo.setMoney(profit.getTotalAmount());
            }
            userAuthInfo.setHas(0);
            return userAuthInfo;
        }
    }

    @Override
    public UserAuthInfo doUserAuth(String userId, String name, String idCard) throws Exception {
        List<UserAuthInfo> infos = customerMapper.checkUserAuth(userId);

        if (CollectionUtils.isEmpty(infos)) {
            UserAuthentication auth = new UserAuthentication();
            auth.setId(UUIDGenerator.generate());
            auth.setUserId(userId);
            auth.setCreateTime(new Date());
            auth.setUserName(name);
            auth.setIdCard(idCard);
            auth.setStates(0);
            auth.setDeleted(0);
            auth.setUpdateTime(auth.getCreateTime());
            userAuthenticationMapper.insert(auth);

            UserAuthInfo info = new UserAuthInfo();
            info.setIdCard(idCard).setName(name).setHas(0);
            UserProfitInfo profit = customerMapper.selectUserProfit(userId);
            if (profit != null) {
                info.setMoney(profit.getTotalAmount());
            }
            return info;
        } else {
            UserAuthInfo info = infos.get(0);
            info.setIdCard(idCard).setName(name);
            String temp = info.getTemp();
            int i = userAuthenticationMapper.updateUserAuth(temp, name, idCard, new Date());
            info.setTemp(null);
            UserProfitInfo profit = customerMapper.selectUserProfit(userId);
            if (profit != null) {
                info.setMoney(profit.getTotalAmount());
            }
            return info;
        }
    }

    @Autowired
    ApplicationContext applicationContext;

    @Override
    public String findUserShareMini(String userId) throws Exception {

        WxUser wxUser = wxUserMapper.selectById(userId);
        if (wxUser == null) {
            throw new NoSuchObjectException("该用户不存在");
        }

        UserShareMini userShareMini = customerMapper.selectUserShareMiniCode(userId);
        if (userShareMini != null) {
            String miniUrl = userShareMini.getMiniUrl();
            applicationContext.publishEvent(new ShareMiniEvent(2, userShareMini));
            return miniUrl;
        }

        MySelfCodeUnLimit getwxacodeunlimit = new MySelfCodeUnLimit();

        getwxacodeunlimit.setAuto_color(true);
        getwxacodeunlimit.setScene(userId);
        getwxacodeunlimit.setWidth(430);
        getwxacodeunlimit.setPage("pages/list/list");
        LineColor lineColor = new LineColor();
        lineColor.setR("");
        lineColor.setG("");
        lineColor.setB("");
        getwxacodeunlimit.setIs_hyaline(true);
        getwxacodeunlimit.setLine_color(lineColor);

        BufferedImage bufferedImage = WxaAPI.getwxacodeunlimit(getRightAccessToken(), getwxacodeunlimit);

        String sendImg = "";

        logger.info("bufferedImage.toString() = " + bufferedImage.toString());


        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ImageOutputStream imageOutput = ImageIO.createImageOutputStream(byteArrayOutputStream);
        ImageIO.write(bufferedImage, "png", imageOutput);
        InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        String png = generateFileName("png");
        String fullPath = "kmzx/share/user/" + png;
        asyncUpload(fullPath, byteArrayInputStream);
        String sendPath = qiNiuConfig.getDomainHost() + fullPath;
        sendImg = sendPath;

        Date now = new Date();
        UserShareMini shareMini = new UserShareMini();
        shareMini.setId(UUIDGenerator.generate());
        shareMini.setCreateTime(now);
        shareMini.setDeleted(0);
        shareMini.setUserId(userId);
        shareMini.setKinds(1);
        shareMini.setMiniUrl(sendImg);

        applicationContext.publishEvent(new ShareMiniEvent(1, shareMini));
        return sendImg;
    }

    @Override
    public List<String> findSpecificUser() {

        return null;
    }

    @Override
    public void updateUserInfo(String userId, String nickName, String avatar) {
        logger.info("更新用户信息,{},{},{}", userId, nickName, avatar);
        wxUserMapper.updateUserInfo(userId, nickName, avatar, new Date());
        logger.info("更新用户信息,OK");
    }

    @Override
    public void updateUserInfoAll(String userId, String nickName, String avatar, String unionId) {
        logger.info("更新用户信息,{},{},{}", userId, nickName, avatar);
        wxUserMapper.updateUserUnionId(userId, nickName, avatar, unionId, new Date());
        logger.info("更新用户信息,OK");
    }

    @Override
    public boolean checkUserUnionId(String userId) {
        WxUser wxUser = wxUserMapper.selectById(userId);
        String unionId = wxUser.getUnionId();
        if (unionId != null && !"".equals(unionId)) {
            return true;
        } else {
            return false;
        }
    }


    public BigDecimal getUserProfit(String userId) {
        List<UserProfit> userProfits = userProfitMapper.selectByUserId(userId);
        if (!CollectionUtils.isEmpty(userProfits)) {
            BigDecimal profitMoney = userProfits.get(0).getAccountMoney();
            return profitMoney;
        }
        return BigDecimal.ZERO;
    }

    /**
     * 异步上传数据
     *
     * @param fileName
     * @param input
     */
    public void asyncUpload(String fileName, InputStream input) {
        Configuration cfg = new Configuration(Zone.huanan());
        UploadManager uploadManager = new UploadManager(cfg);
        String accessKey = qiNiuConfig.getAppKey();
        String secretKey = qiNiuConfig.getAppSecret();
        String bucket = qiNiuConfig.getBucketName1();
        Auth auth = Auth.create(accessKey, secretKey);
        String upToken = auth.uploadToken(bucket);
        try {
            Response response = uploadManager.put(input, fileName, upToken, null, null);
            //解析上传成功的结果
            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
            logger.info("请求返回的数据key:{}", putRet.key);
            logger.info("请求返回的数据Hash:{}", putRet.hash);
        } catch (QiniuException ex) {
            Response r = ex.response;
            System.err.println(r.toString());
            try {
                System.err.println(r.bodyString());
            } catch (QiniuException ex2) {
            }
        }
    }

    public String getRightAccessToken() {
        Object obj = stringObjectRedisTemplate.opsForValue().get("messageToken");
        String wxTokens = null;
        if (obj != null) {
            String mt = (String) obj;
            wxTokens = mt;
        } else {
            Token token = TokenAPI.token(wxConfig.getAppId(), wxConfig.getAppSecret());
            String access_token = token.getAccess_token();
            int secend = token.getExpires_in();
            wxTokens = access_token;
            stringObjectRedisTemplate.opsForValue().set("messageToken", access_token, 7100, TimeUnit.SECONDS);
        }
        return wxTokens;
    }


    @Autowired
    private AtomicInteger atomicInteger;

    public String generateFileName(String fileType) {
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        StringBuilder sb = new StringBuilder();
        sb.append(year);
        sb.append("/");
        sb.append(calendar.get(Calendar.MONTH) + 1);
        sb.append("/");
        sb.append(calendar.get(Calendar.DAY_OF_MONTH));
        sb.append("-");
        sb.append(calendar.get(Calendar.HOUR_OF_DAY));// 1位
        sb.append(calendar.get(Calendar.MINUTE));// 1位
        sb.append(calendar.get(Calendar.SECOND));// 1位
        sb.append("-");
        sb.append(atomicInteger.getAndIncrement());
        sb.append(RandomStringUtils.randomAlphanumeric(6));
        sb.append(".");
        sb.append(fileType);
        return sb.toString();
    }

    public List<FansInfo> haveNext(String userId) {
        Page<FansInfo> pager = userInviteMapper.selectUserFans(userId, null);
        List<FansInfo> result = pager.getResult();
        for (int i = 0; i < result.size(); i++) {
            List<FansInfo> list1 = haveNext(result.get(i).getUserId());
            result.addAll(list1);
        }
        return result;
    }

    public List<String> haveNext2(String userId) {
        Page<String> pager = userInviteMapper.selectRecursionUserFans(userId);
        List<String> result = pager.getResult();
        for (int i = 0; i < result.size(); i++) {
            List<String> list1 = haveNext2(result.get(i));
            result.addAll(list1);
        }
        return result;
    }


    @Override
    public UserCertInfo checkUserCertInfo(String userId) {
        List<UserCertInfo> infos = customerMapper.selectUserCertInfo(userId);

        if (CollectionUtils.isEmpty(infos)) {
            UserCertInfo info = new UserCertInfo();
            // 1 代表没有认证
            info.setHas(1);
            return info;
        } else {
            UserCertInfo certInfo = infos.get(0);
            certInfo.setHas(0);
            UserProfitInfo profit = customerMapper.selectUserProfit(userId);
            if (profit != null) {
                certInfo.setMoney(profit.getCanPay());
            }
            return certInfo;
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void doUserCertInfo(UserCert userCert) {
        String id = UUIDGenerator.generate();
        Date date = new Date();
        UserBankCert bankCert = new UserBankCert();
        String username = userCert.getUsername();
        if (username == null || "".equals(username)) {
            throw new NoSuchObjectException("姓名不可为空");
        }
        String phone = userCert.getPhone();
        if (phone == null || "".equals(phone)) {
            throw new NoSuchObjectException("手机号不可为空");
        }
        String bankCard = userCert.getBankCard();
        if (bankCard == null || "".equals(bankCard)) {
            throw new NoSuchObjectException("银行卡号不可为空");
        }
        if (bankCard.length() < 14 || bankCard.length() > 22) {
            throw new NoSuchObjectException("银行卡号长度不正确,请核查!");
        }
        String idCard = userCert.getIdCard();
        if (idCard == null || "".equals(idCard)) {
            throw new NoSuchObjectException("身份证号不可为空");
        }
        if (idCard.length() < 15 || idCard.length() > 19) {
            throw new NoSuchObjectException("身份证号长度不正确,请核查!");
        }

        String idCardFront = userCert.getIdCardFront();
        if (idCardFront == null || "".equals(idCardFront)) {
            throw new NoSuchObjectException("身份证正面照不可为空");
        }
        String idCardBack = userCert.getIdCardBack();
        if (idCardBack == null || "".equals(idCardBack)) {
            throw new NoSuchObjectException("身份证反面照不可为空");
        }

        bankCert.setId(id).setCreateTime(date).setUpdateTime(date);
        bankCert.setUserId(userCert.getUserId()).setUsername(username);
        bankCert.setBankCard(userCert.getBankCard()).setPhone(userCert.getPhone());
        bankCert.setDeleted(0).setStates(0).setIdCard(idCard);
        bankCert.setIdCardFront(userCert.getIdCardFront()).setIdCardBack(userCert.getIdCardBack());

        customerMapper.banUserBankCert(userCert.getUserId(), date);
        customerMapper.insertUserBankCert(bankCert);
        logger.info("用户银行卡信息绑定_完成,{}", userCert);
    }

    @Override
    public UserVerifyInfo checkUserVerifyInfo(String userId) {
        UserVerifyInfo info = new UserVerifyInfo();
        info.setHas(0);

        List<UserVerifyInfo> infos = customerMapper.selectUserVerifyInfo(userId);
        if (info != null && infos.size() > 0) {
            UserVerifyInfo verifyInfo = infos.get(0);
            String idCard = verifyInfo.getIdCard();
            String username = verifyInfo.getUsername();
            String phone = verifyInfo.getPhone();
            info.setPhone(phone).setUsername(username).setIdCard(idCard).setHas(1).setSameWx(verifyInfo.getSameWx());
            info.setReason(verifyInfo.getReason());
        }
        return info;
    }

    @Override
    public void doUserVerifyInfo(String userId, String username, String idCard, String phone) throws Exception {
        if (idCard == null || "".equals(idCard)) {
            throw new NoSuchObjectException("身份证号不可为空");
        }

        if (!IdCardUtil.isValidatedAllIdcard(idCard)) {
            throw new NoSuchObjectException("身份证号有误!");
        }
        idCard = idCard.toUpperCase();

        long lastMicroSeconds = Duration.between(LocalDateTime.now(), LocalDateTime.of(LocalDate.now(), LocalTime.MAX)).getSeconds();
        Object s = stringObjectRedisTemplate.opsForValue().get("idCardVerify:" + userId);
        if (s != null) {
            int num = Integer.parseInt(s.toString());
            if (num > 9) {
                throw new NoSuchObjectException("今日认证次数已用完,请明日再试");
            }
            num += 1;
            // , lastMicroSeconds, TimeUnit.MICROSECONDS
            stringObjectRedisTemplate.opsForValue().set("idCardVerify:" + userId, num + "", lastMicroSeconds, TimeUnit.SECONDS);
        } else {
            //, lastMicroSeconds, TimeUnit.MICROSECONDS
            stringObjectRedisTemplate.opsForValue().set("idCardVerify:" + userId, 1 + "", lastMicroSeconds, TimeUnit.SECONDS);
        }

        List<UserVerifyInfo> sameInfo = customerMapper.selectUserVerifyInfoOK(userId, SameWxEnum.SAME_WX.getCode());
        if (sameInfo != null && sameInfo.size() > 0) {
            String id = sameInfo.get(0).getT();
            customerMapper.updateUserVerifyPhone(id, phone, new Date());
            logger.info("该用户已经有实名信息了,{},{},{},{}", userId, username, idCard, phone);
        } else {
            List<UserVerifyInfo> infos = customerMapper.selectSameUserVerifyInfo(username, idCard);
            int states = IdCardEnum.Normal_Ok.getCode();
            if (infos != null && infos.size() > 0) {
                states = IdCardEnum.Verify_OK.getCode();
//

                Object keyPatchO = stringObjectRedisTemplate.opsForValue().get(Constants.wx_patch_update + userId);
                if (keyPatchO != null) {
                    String keyPatch = keyPatchO.toString();
                    String[] orderIdCodes = keyPatch.split("_");
                    String orderId = orderIdCodes[0];
                    String orderCode = orderIdCodes[1];
                    WXSeaInfo info = wxPayMapper.selectPreSendInfo(orderId);
                    if (info != null) {
                        String signStr = null;
                        String reqHeader = null;
                        signStr = genSign(idCard, username, info.getOrderCodes(), info.getWxOrderNo());
                        reqHeader = makeReqHeader(idCard, username, info.getOrderCodes(), info.getWxOrderNo(), signStr);
                        HttpUriRequest request = getHttpUriRequest(reqHeader, 1);
                        CloseableHttpResponse execute = LocalHttpClient.execute(request);
                        HttpEntity entity = execute.getEntity();
                        String str = EntityUtils.toString(entity, "UTF-8");
                        logger.info("微信支付,报关返回的数据:{}", str);
                        WxSeaGateResponse result = WxSeaGateResponse.fromXML(str);
                        String returnCode = result.getReturn_code();
                        String resultCode = result.getResult_code();

                        if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {
                            String cert_check_result = result.getCert_check_result();
                            if ("DIFFERENT".equals(cert_check_result)) {
                                throw new NoSuchObjectException("您的订单: [" + orderCode + "] 实名信息与微信不一致,请核验后重试");
                            } else if ("SAME".equals(cert_check_result)) {
                                UserVerify verify = new UserVerify();
                                Date date = new Date();
                                verify.setId(UUIDGenerator.generate())
                                        .setDeleted(DeletedEnum.Exists_OK.getCode()).setStates(IdCardEnum.Verify_OK.getCode()).setSameWx(SameWxEnum.SAME_WX.getCode())
                                        .setUserId(userId).setUsername(username)
                                        .setIdCard(idCard).setPhone(phone)
                                        .setCardUser("").setReason("OK")
                                        .setCardBack("").setCardFront("")
                                        .setRemark("").setUpdateTime(date)
                                        .setCreateTime(date);
                                customerMapper.insertUserVerifyInfo(verify);
                                logger.info("微信校验后,核实,更新用户实名信息ok,{}", verify);
                                customerMapper.batchDelUserVerify(userId, verify.getId());
                                stringObjectRedisTemplate.delete(Constants.wx_patch_update + userId);
                                ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
                                opsForValue.set(Constants.push_file_gate + orderId + "_" + info.getTradeNum(), orderId, 2, TimeUnit.SECONDS);
                            }
                        }
                    } else {
                        UserVerify verify = new UserVerify();
                        Date date = new Date();
                        verify.setId(UUIDGenerator.generate())
                                .setDeleted(DeletedEnum.Exists_OK.getCode()).setStates(states).setSameWx(SameWxEnum.SAME_WX.getCode())
                                .setUserId(userId).setUsername(username)
                                .setIdCard(idCard).setPhone(phone)
                                .setCardBack("").setCardFront("")
                                .setCardUser("").setReason("OK")
                                .setRemark("").setUpdateTime(date)
                                .setCreateTime(date);
                        customerMapper.insertUserVerifyInfo(verify);
                        customerMapper.batchDelUserVerify(userId, verify.getId());
                        logger.info("新增用户实名信息ok,{}", verify);
                    }
                } else {
                    UserVerify verify = new UserVerify();
                    Date date = new Date();
                    verify.setId(UUIDGenerator.generate())
                            .setDeleted(DeletedEnum.Exists_OK.getCode()).setStates(states).setSameWx(SameWxEnum.SAME_WX.getCode())
                            .setUserId(userId).setUsername(username)
                            .setIdCard(idCard).setPhone(phone)
                            .setCardBack("").setCardFront("")
                            .setCardUser("").setReason("OK")
                            .setRemark("").setUpdateTime(date)
                            .setCreateTime(date);
                    customerMapper.insertUserVerifyInfo(verify);
                    customerMapper.batchDelUserVerify(userId, verify.getId());
                    logger.info("新增用户实名信息ok,{}", verify);
                }
                return;
            }

            int i = aliVerifyIdCard(idCard, username);
            if (i == 20010) {
                throw new NoSuchObjectException("身份证号为空或非法!");
            } else if (i == 20310) {
                throw new NoSuchObjectException("姓名为空或非法!");

            } else if (i == 1) {


                Object keyPatchO = stringObjectRedisTemplate.opsForValue().get(Constants.wx_patch_update + userId);

                if (keyPatchO != null) {
                    String keyPatch = keyPatchO.toString();
                    String[] orderIdCodes = keyPatch.split("_");
                    String orderId = orderIdCodes[0];
                    String orderCode = orderIdCodes[1];
                    WXSeaInfo info = wxPayMapper.selectPreSendInfo(orderId);
                    if (info != null) {
                        String signStr = null;
                        String reqHeader = null;
                        signStr = genSign(idCard, username, info.getOrderCodes(), info.getWxOrderNo());
                        reqHeader = makeReqHeader(idCard, username, info.getOrderCodes(), info.getWxOrderNo(), signStr);
                        HttpUriRequest request = getHttpUriRequest(reqHeader, 1);
                        CloseableHttpResponse execute = LocalHttpClient.execute(request);
                        HttpEntity entity = execute.getEntity();
                        String str = EntityUtils.toString(entity, "UTF-8");
                        logger.info("微信支付,报关返回的数据:{}", str);
                        WxSeaGateResponse result = WxSeaGateResponse.fromXML(str);
                        String returnCode = result.getReturn_code();
                        String resultCode = result.getResult_code();

                        if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {
                            String cert_check_result = result.getCert_check_result();
                            if ("DIFFERENT".equals(cert_check_result)) {
                                throw new NoSuchObjectException("您的订单: [" + orderCode + "] 实名信息与微信不一致,请核验后重试");
                            } else if ("SAME".equals(cert_check_result)) {
                                UserVerify verify = new UserVerify();
                                Date date = new Date();
                                verify.setId(UUIDGenerator.generate())
                                        .setDeleted(DeletedEnum.Exists_OK.getCode()).setStates(IdCardEnum.Verify_OK.getCode()).setSameWx(SameWxEnum.SAME_WX.getCode())
                                        .setUserId(userId).setUsername(username)
                                        .setIdCard(idCard).setPhone(phone)
                                        .setCardUser("").setReason("OK")
                                        .setCardBack("").setCardFront("")
                                        .setRemark("").setUpdateTime(date)
                                        .setCreateTime(date);
                                customerMapper.insertUserVerifyInfo(verify);
                                logger.info("微信校验后,核实,更新用户实名信息ok,{}", verify);
                                customerMapper.batchDelUserVerify(userId, verify.getId());
                                stringObjectRedisTemplate.delete(Constants.wx_patch_update + userId);
                                ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
                                opsForValue.set(Constants.push_file_gate + orderId + "_" + info.getTradeNum(), orderId, 2, TimeUnit.SECONDS);
                            }
                        }
                    } else {
                        UserVerify verify = new UserVerify();
                        Date date = new Date();
                        verify.setId(UUIDGenerator.generate())
                                .setDeleted(DeletedEnum.Exists_OK.getCode()).setStates(states).setSameWx(SameWxEnum.SAME_WX.getCode())
                                .setUserId(userId).setUsername(username)
                                .setIdCard(idCard).setPhone(phone)
                                .setCardBack("").setCardFront("")
                                .setCardUser("").setReason("OK")
                                .setRemark("").setUpdateTime(date)
                                .setCreateTime(date);
                        customerMapper.insertUserVerifyInfo(verify);
                        customerMapper.batchDelUserVerify(userId, verify.getId());
                        logger.info("新增用户实名信息ok,{}", verify);
                    }
                } else {
                    UserVerify verify = new UserVerify();
                    Date date = new Date();
                    verify.setId(UUIDGenerator.generate())
                            .setDeleted(DeletedEnum.Exists_OK.getCode()).setStates(IdCardEnum.Verify_OK.getCode()).setSameWx(SameWxEnum.SAME_WX.getCode())
                            .setUserId(userId).setUsername(username)
                            .setIdCard(idCard).setPhone(phone)
                            .setCardBack("").setCardFront("")
                            .setCardUser("").setReason("OK")
                            .setRemark("").setUpdateTime(date)
                            .setCreateTime(date);
                    customerMapper.insertUserVerifyInfo(verify);
                    logger.info("新增用户实名信息ok,{}", verify);
                }

            } else if (i == 2) {
                throw new NoSuchObjectException("姓名和身份证号码不匹配!");
            } else if (i == 3) {
                throw new NoSuchObjectException("抱歉,暂无您的身份证信息!");
            } else {
                throw new NoSuchObjectException("抱歉,暂无您的身份证信息!");
            }
        }


    }

    /**
     * 温馨提示：
     * 1.解析结果时，先判断code
     * 2.出现'无记录'时，有以下几种原因
     * (1)现役军人、武警官兵、特殊部门人员及特殊级别官员；
     * (2)退役不到2年的军人和士兵（根据军衔、兵种不同，时间会有所不同，一般为2年）；
     * (3)户口迁出，且没有在新的迁入地迁入；
     * (4)户口迁入新迁入地，当地公安系统未将迁移信息上报到公安部（上报时间地域不同而有所差异）；
     * (5)更改姓名，当地公安系统未将更改信息上报到公安部（上报时间因地域不同而有所差异）；
     * (6)移民；
     * (7)未更换二代身份证；
     * (8)死亡。
     * (9)身份证号确实不存在
     * {
     * "code": "0", //返回码，0：成功，非0：失败（详见错误码定义）
     * //当code=0时，再判断下面result中的res；当code!=0时，表示调用已失败，无需再继续
     * "message": "成功", //返回码说明
     * "result": {
     * "name": "冯天", //姓名
     * "idcard": "350301198011129422", //身份证号
     * "res": "1", //核验结果状态码，1 一致；2 不一致；3 无记录
     * "description": "一致",  //核验结果状态描述
     * "sex": "男",
     * "birthday": "19940320",
     * "address": "江西省南昌市东湖区"
     * }
     * }
     * <p>
     * 错误码  	错误信息	                描述
     * 0	    成功  	                成功
     * 400	    参数错误	                参数错误
     * 20010	身份证号为空或非法	        身份证号为空或非法
     * 20310	姓名为空或非法     	    姓名为空或非法
     * 404	    请求资源不存在	            请求资源不存在
     * 500	    系统内部错误，请联系服务商	系统内部错误，请联系服务商
     * 501	    第三方服务异常	            第三方服务异常
     * 604	    接口停用	                接口停用
     * 1001	    其他，以实际返回为准	    其他，以实际返回为准
     * https://market.aliyun.com/products/57000002/cmapi026109.html?spm=5176.2020520132.101.9.747572186jJnvw#sku=yuncode2010900004
     *
     * @param idCard
     * @param username
     */
    public int aliVerifyIdCard(String idCard, String username) {
        try {
            Map<String, String> headers = new HashMap<String, String>();
            headers.put("Authorization", "APPCODE " + aliConfig.getIdVerifyCode());
            Map<String, String> querys = new HashMap<>();
            querys.put("idcard", idCard);
            querys.put("name", username);

            String response = HttpClientUtil.postRequest(aliConfig.getIdVerifyAddress(), querys, headers);
            logger.info("调用 阿里云 接口【身份证查询】返回数据 {}", response);

            JSONObject verify = JSONObject.parseObject(response);
            String code = verify.getString("code");
            if ("0".equals(code)) {
                JSONObject result = verify.getJSONObject("result");
                String res = result.getString("res");
                if ("1".equals(res)) {
                    return 1;
                } else if ("2".equals(res)) {
                    return 2;
                } else if ("3".equals(res)) {
                    return 3;
                }
            } else {
                return Integer.parseInt(code);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return 3;
    }

    @Autowired
    private WXDataConfig wxDataConfig;

    public String genSign(String idCard, String username, String orderCodes, String wxOrderNo) {
        SortedMap<String, Object> sortMap = new TreeMap();
        sortMap.put("appid", wxDataConfig.getAppId());
        sortMap.put("mch_id", wxDataConfig.getMerchantNum());
        sortMap.put("out_trade_no", orderCodes);
        sortMap.put("transaction_id", wxOrderNo);
        sortMap.put("customs", wxDataConfig.getCustoms());
        sortMap.put("mch_customs_no", wxDataConfig.getMchCustomsNo());
        sortMap.put("action_type", "MODIFY");
        sortMap.put("cert_type", "IDCARD");
        sortMap.put("cert_id", idCard);
        sortMap.put("name", username);


        StringBuilder strb = new StringBuilder();


        Set<String> keySet = sortMap.keySet();
        for (String key : keySet) {
            Object value = sortMap.get(key);
            strb.append(key).append("=").append(value);
            strb.append("&");
        }

        strb.append("key=").append(wxDataConfig.getMerchantKey());

        String signStr = DigestUtils.md5Hex(strb.toString()).toUpperCase();
        return signStr;
    }

    public String makeReqHeader(String idCard, String username, String orderCodes, String wxOrderNo, String sign) {

        StringBuilder sb = new StringBuilder();
        sb.append("<xml>");

        sb.append("<appid>");
        sb.append(wxDataConfig.getAppId());
        sb.append("</appid>");

        sb.append("<mch_id>");
        sb.append(wxDataConfig.getMerchantNum());
        sb.append("</mch_id>");


        sb.append("<out_trade_no>");
        sb.append(orderCodes);
        sb.append("</out_trade_no>");

        sb.append("<transaction_id>");
        sb.append(wxOrderNo);
        sb.append("</transaction_id>");

        sb.append("<customs>");
        sb.append(wxDataConfig.getCustoms());
        sb.append("</customs>");

        sb.append("<mch_customs_no>");
        sb.append(wxDataConfig.getMchCustomsNo());
        sb.append("</mch_customs_no>");

        sb.append("<action_type>");
        sb.append("MODIFY");
        sb.append("</action_type>");

        sb.append("<cert_type>");
        sb.append("IDCARD");
        sb.append("</cert_type>");

        sb.append("<cert_id>");
        sb.append(idCard);
        sb.append("</cert_id>");

        sb.append("<name>");
        sb.append(username);
        sb.append("</name>");

        sb.append("<sign>");
        sb.append(sign);
        sb.append("</sign>");


        sb.append("</xml>");
        return sb.toString();
    }

    public HttpUriRequest getHttpUriRequest(String xmlStringContent, int kinds) {
        String url = "";
        if (kinds == 1) {
            url = wxDataConfig.getSeaGateUrl();
        }
        Header xmlHeader = new BasicHeader(HttpHeaders.CONTENT_TYPE, ContentType.create("application/xml", "UTF-8").toString());
        HttpUriRequest httpUriRequest = RequestBuilder.post()
                .setHeader(xmlHeader)
                .setUri(url)
                .setEntity(new StringEntity(xmlStringContent, Charset.forName("utf-8")))
                .build();
        return httpUriRequest;
    }
}
